#ifndef __SCHED_H_
#define __SCHED_H_

#include <list.h>
#include <type.h>
#include <task.h>
#include <timer.h>

typedef struct run_queue
{
    struct list_head rq_head;
    unsigned int nr_running;
    u64 nr_switches;
    task_struct *curr;
} run_queue;

struct sched_class {
    const struct sched_class *next;

    void (*task_fork)(task_struct *p);
    void (*enqueue_task)(run_queue *rq, task_struct *p);
    void (*dequeue_task)(run_queue *rq, task_struct *p);
    void (*task_tick)(run_queue *rq, task_struct *p);
    task_struct *(*pick_next_task)(run_queue *rq,
            task_struct *prev);
};

extern const struct sched_class simple_sched_class;

void sched_init(void);

void wake_up_process(struct task_struct *p);

register unsigned long current_stack_pointer asm("sp");

static inline task_struct *get_current(){
    return (task_struct *)(current_stack_pointer & ~(THREAD_SIZE - 1));
}

#define current get_current()
#define preempt_counter() (current->preempt_count)

static inline void preempt_disable(){
    current->preempt_count++;
}


static inline void preempt_enable(){
    current->preempt_count--;
}

extern union task_union init_task_union;




#define for_each_task(p) \
	for (p = &init_task; (p = p->next_task) != &init_task; )

#define list_entry(ptr, type, member) \
	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

#define list_for_each(pos, head) \
	for (pos = (head)->next; pos != (head); pos = pos->next)

#define DEF_COUNTER (HZ/10)  /* 100ms time slice */

/* 0号进程即init进程 */
#define INIT_TASK(task) \
{                      \
	.state = 0,     \
	.priority = 20,   \
	.counter = DEF_COUNTER, \
	.flags = PF_KTHREAD,   \
	.pid = 0,     \
	.preempt_count = 0, \
	.need_resched = 0, \
	.next_task = (struct task_struct *)&task, \
	.prev_task = (struct task_struct *)&task, \
}

static inline void clear_task_resched(struct task_struct *p)
{
	p->need_resched = 0;
}

void tick_handle_periodic();

#define PREEMPT_BITS	8
#define HARDIRQ_BITS	4

#define PREEMPT_SHIFT	0
#define HARDIRQ_SHIFT	(PREEMPT_SHIFT + PREEMPT_BITS)

#define PREEMPT_OFFSET	(1UL << PREEMPT_SHIFT)
#define HARDIRQ_OFFSET	(1UL << HARDIRQ_SHIFT)


#endif // !__SCHED_H_